/*
    Geocache: some utilities for managing and visualizing geocache information
    Copyright (C) 2008  Gary Jackson

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/*
 * ConvexHull.java
 */

package com.thegbomb.geocache;

import com.thegbomb.common.CommandLine;
import com.thegbomb.common.CommandLine.Action;
import com.thegbomb.common.CommandLine.UsageException;
import com.thegbomb.common.FileCollection;
import com.thegbomb.common.MapIterator;
import com.thegbomb.sphere.Point;
import com.thegbomb.sphere.Polygon;
import com.thegbomb.sphere.PropertiesPointSet;
import com.thegbomb.sphere.PropertiesPolygon;
import com.thegbomb.sphere.Util;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.io.Reader;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.xml.transform.TransformerException;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;

/**
 *
 * @author Gary Jackson
 */
public class ConvexHull {
    static private Logger logger = Logger.getLogger(ConvexHull.class);
    
    static private final double EARTH_RADIUS = 6372.795d; /* km */
    
    private static void header(PrintStream out, String name) {
        out.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
        out.println("<kml xmlns=\"http://earth.google.com/kml/2.2\">");
        out.println("<Document>");
        out.println("    <name>" + name + "</name>");
        out.println("    <Style id=\"style\">");
        out.println("        <LineStyle>");
        out.println("            <color>ffffffff</color>");
        out.println("            <colorMode>random</colorMode>");
        out.println("            <width>2</width>");
        out.println("        </LineStyle>");
        out.println("        <PolyStyle>");
        out.println("            <color>40ffffff</color>");
        out.println("            <colorMode>random</colorMode>");
        out.println("        </PolyStyle>");
        out.println("    </Style>");
    }
    
    private static void polygon(PrintStream out, String name, Polygon polygon) {
        List<Point> points = polygon.getPoints();
        
        String areaStr = String.format("%.2f", polygon.getArea()*EARTH_RADIUS*EARTH_RADIUS);
        String periStr = String.format("%.2f", polygon.getPerimiter()*EARTH_RADIUS);
        
        out.println("    <Placemark>");
        out.println("        <name>" + name + "</name>");
        out.println("        <styleUrl>#style</styleUrl>");
        out.println("        <description>");
        out.println("Area: " + areaStr + " km**2");
        out.println("Perimiter: " + periStr + " km");
        out.println("        </description>");
        out.println("        <Polygon>");
        out.println("             <outerBoundaryIs><LinearRing><coordinates>");
        
        for (Point p: points) {
            out.println("                 " + Util.toDeg(p.getPhi()) + "," + Util.toDeg(p.getTheta()) + ",0");
        }
        
        Point p = points.get(0);
        out.println("                 " + Util.toDeg(p.getPhi()) + "," + Util.toDeg(p.getTheta()) + ",0");
        
        out.println("             </coordinates></LinearRing></outerBoundaryIs>");
        out.println("        </Polygon>");
        out.println("    </Placemark>");
    }
    
    private static void footer(PrintStream out) {
        out.println("</Document>");
        out.println("</kml>");
    }
    
    private static PrintStream out = System.out;
    private static Set<File> inputs = new HashSet<File>();
    
    /**
     * Run the ConvexHull program.
     * @param args the command line arguments
     */
    public static void main(String[] args) throws IOException, TransformerException {
        BasicConfigurator.configure();
        
        CommandLine command = new CommandLine(true);
        command.addAction("out", new Action(){
            public void act(String option, String argument) throws UsageException {
                try {
                    out = new PrintStream(new BufferedOutputStream(new FileOutputStream(new File(argument))));
                } catch (FileNotFoundException e) {
                    throw new UsageException("could not access " + argument + ": " + e.getMessage());
                }
            }
            public boolean isArgument() { return true; }
            public boolean isMultiplicity() { return false; }
            public boolean isRequired() { return false; }
        });
        command.addAction("indir", new Action(){
            public void act(String option, String argument) throws UsageException {
                try {
                    inputs.addAll(new FileCollection(new File(argument), GpxMinusWpts.getInstance(), false));
                } catch (IOException e) {
                    throw new UsageException("could not access " + argument + ": " + e.getMessage());
                }
            }
            public boolean isArgument() { return true; }
            public boolean isMultiplicity() { return true; }
            public boolean isRequired() { return false; }
        });
        
        List<String> filenames;
        try {
            filenames = command.process(args);
        } catch (UsageException e) {
            command.printUsage(System.err, Fetch.class.getName(), e);
            return;
        }
        
        for (String s: filenames) {
            inputs.add(new File(s));
        }

        Iterator<Reader> f2r = new MapIterator<File, Reader>(inputs.iterator(), new FileToReader());
        Iterator<PropertiesPointSet> r2ps = new MapIterator<Reader, PropertiesPointSet>(f2r, new GpxToPointSet());
        Iterator<PropertiesPolygon> ps2h = new MapIterator<PropertiesPointSet, PropertiesPolygon>(r2ps, new PointSetToHull());
        
        header(out, "Pocket Query Coverage");
        PropertiesPolygon p = null;
        while (ps2h.hasNext()) {
            p = ps2h.next();
            polygon(out, (String)p.getProperty("name"), p);
        }
        footer(out);
        
        out.flush();
        out.close();
    }
}
